// Copyright(c) 2008 Tri Tech Information Systems Inc. 
// Distributed under the Boost Software License, Version 1.0.
//     (See accompanying file ../../LICENSE_1_0.txt or copy at
//           http://www.boost.org/LICENSE_1_0.txt)
//     

#ifndef PYTHON_TTYPES_POINTER_H
#define PYTHON_TTYPES_POINTER_H
// Boost.Python allows the registration of by-value converters.
// However, it does not offer the same in the case of pointers.
// This, of course, is understandable, but its a real pain when trying to generate wrappers.
// In a well-designed API, simply by looking at the type, we can determine the correct passing method
#include <boost/python.hpp>



class PointerApi
{
    public:

    virtual boost::python::object to_python(const void * ptr, boost::python::type_info info) = 0;
    virtual void register_to_python(boost::python::type_info info, boost::python::object (*convertor)(const void*) ) = 0;
};

static PointerApi * GetPointerApi()
{
    using namespace boost::python;
    static PointerApi * api = 0;
    if( !api )
    {
        object api_obj = import("pyxx_helper").attr("_pointer_api");
        api = reinterpret_cast<PointerApi*>(PyCObject_AsVoidPtr(api_obj.ptr()));
    }
    return api;
}

template<typename ClassType>
boost::python::object handle_ptr(const ClassType * ptr)
{
    return GetPointerApi()->to_python(ptr, boost::python::type_id<ClassType>());
}

template<typename ClassType>
boost::python::object handle_ref(const ClassType & ptr)
{
    return handle_ptr<ClassType>(&ptr);
}


template<typename ClassType>
void add_pointer_handler( boost::python::object (*convertor)(const void*) )
{
    GetPointerApi()->register_to_python(boost::python::type_id<ClassType>(), convertor);
}

template<typename ClassType>
struct pass_ptr_by_reference
{
    pass_ptr_by_reference()
    {
        add_pointer_handler<ClassType>( &pass_ptr_by_reference<ClassType>::from_ptr );
    }

    static boost::python::object from_ptr(const void * vptr)
    {
        using namespace boost::python;
        return object( ptr( reinterpret_cast<const ClassType*>(vptr) ) );
    }
};

template<typename ClassType>
struct pass_ptr_by_value
{
    pass_ptr_by_value()
    {
        add_pointer_handler<ClassType>( &pass_ptr_by_value<ClassType>::from_ptr );
    }

    static boost::python::object from_ptr(const void * vptr)
    {
        using namespace boost::python;
        return object( reinterpret_cast<const ClassType*>(vptr) );
    }
};

struct return_handled_ptr_impl
{
    struct holder
    {
        template <class T>
        static PyObject * execute(T * p)
        {
            return boost::python::incref(handle_ptr(p).ptr());
        }        
    };


    template <class T>
    struct apply        
    {
        typedef boost::python::to_python_indirect<T, holder> type;
    };
};

struct return_handled_ptr : public boost::python::return_value_policy<return_handled_ptr_impl>
{};   


template<typename Type>
struct pointer_safe
{
    static Type get(Type type)
    {
        return type;
    }
};


template<typename Type>
struct pointer_safe<Type*>
{
    static boost::python::object get(Type * type)
    {
        return handle_ptr(type);
    }
};


#endif
